/*
抽象层的实现
*/

#include <iostream>
#include <string>
#include <memory>
#include <functional>
#include "Fields.hpp"

#pragma once

namespace RpcModule
{
    // 1. 针对网络传输的消息，进行消息基类的抽象
    class BaseMessage
    {
    public:
        using ptr = std::shared_ptr<BaseMessage>;
        virtual ~BaseMessage() {}
        // 设置ID 和 设置消息类型(Rpc请求/应答)
        virtual void SetId(const std::string &id) { _rid = id; }
        virtual void SetMType(MType mtype) { _mtype = mtype; }
        // 获取Id 和 获取消息类型
        virtual std::string GetRid() { return _rid; }
        virtual MType GetMtype() { return _mtype; }
        // 序列化和反序列化
        virtual std::string Serialize() = 0;
        virtual bool UnSerialize(const std::string &msg) = 0;
        // 检查反序列化之后的消息是否合法
        virtual bool Check() = 0;

    private:
        MType _mtype;
        std::string _rid;
    };

    // 2. 进行缓冲区操作的基类
    class BaseBuffer
    {
    public:
        using ptr = std::shared_ptr<BaseBuffer>;
        // 获取可读数据长度
        virtual size_t ReadableSize() = 0;
        // 尝试获取4字节数据，但不删除
        virtual int32_t PeekInt32() = 0;
        // 从缓冲区中删除4字节
        virtual void RetrieveInt32() = 0;
        // 从缓冲区中取出4字节，并删除
        virtual int32_t ReadInt32() = 0;
        // 获取缓冲区中的len长度数据，返回string
        virtual std::string RetrieveAsString(size_t len) = 0;
    };

    // 3. 有消息到来，从缓冲区中获取数据，并且可以发送数据
    // 所以需要提供序列化接口，并且判断缓冲区中的数据是否可以读取
    class BaseProtocol
    {
    public:
        using ptr = std::shared_ptr<BaseProtocol>;
        // 判断缓冲区中的数据是否完整，完整才可以读取
        virtual bool CanProcessed(const BaseBuffer::ptr &buffer) = 0;
        // 有消息，从buffer中获取消息，并将消息反序列化到message中
        virtual bool OnMessage(const BaseBuffer::ptr &buffer, BaseMessage::ptr &message) = 0;
        // 如果要发送数据，需要先序列化 -- LV格式的封装，message中可以进行序列化操作
        virtual std::string Serialize(const BaseMessage::ptr &message) = 0;
    };

    // 4. 对于连接的管理
    class BaseConnection
    {
    public:
        using ptr = std::shared_ptr<BaseConnection>;
        // 发送数据，使用_protocol进行消息的序列化操作
        virtual void Send(const BaseMessage::ptr &message) = 0;
        // 关闭连接
        virtual void ShutDown() = 0;
        // 判断连接是否正常
        virtual bool Connected() = 0;

    private:
        BaseProtocol::ptr _protocol;
    };

    // 5. 服务端的抽象
    // 服务端需要设置三个回调函数，我们先定义出三个回调函数：
    // 连接到来的回调函数，需要对连接进行处理
    using ConnectionCallBack = std::function<void(const BaseConnection::ptr &)>;
    // 连接关闭的回调函数，需要对连接进行处理
    using CloseCallBack = std::function<void(const BaseConnection::ptr &)>;
    // 消息到来的回调函数，对连接和消息同时进行管理
    using MessageCallBack = std::function<void(const BaseConnection::ptr &, BaseMessage::ptr &)>;
    class BaseServer
    {
    public:
        using ptr = std::shared_ptr<BaseServer>;
        virtual void SetConnectionCallBack(const ConnectionCallBack &cb) { _cb_connection = cb; }
        virtual void SetCloseCallBack(const CloseCallBack &cb) { _cb_close = cb; }
        virtual void SetMessageCallBack(const MessageCallBack &cb) { _cb_message = cb; }
        // 服务端的启动
        virtual void Start() = 0;

    protected:
        ConnectionCallBack _cb_connection;
        CloseCallBack _cb_close;
        MessageCallBack _cb_message;
    };

    // 6. 客户端的抽象
    // 客户端不仅要设置回调函数，还需要有一些其它的服务
    class BaseClient
    {
    public:
        using ptr = std::shared_ptr<BaseClient>;
        virtual void SetConnectionCallBack(const ConnectionCallBack &cb) { _cb_connection = cb; }
        virtual void SetCloseCallBack(const CloseCallBack &cb) { _cb_close = cb; }
        virtual void SetMessageCallBack(const MessageCallBack &cb) { _cb_message = cb; }
        // 客户端要连接服务端
        virtual void Connect() = 0;
        // 关闭客户端
        virtual void ShutDown() = 0;
        // 向服务端发送消息
        virtual void Send(const BaseMessage::ptr& message) = 0;
        // 获取当前的连接
        virtual BaseConnection::ptr GetConnetion() = 0;
        // 检查当前连接是否正常
        virtual bool Connected() = 0;

    protected:
        ConnectionCallBack _cb_connection;
        CloseCallBack _cb_close;
        MessageCallBack _cb_message;
    };
}